#include "processdialog.h"
#include "ui_processdialog.h"
#include <QDebug>
#include <QRegExp>
#include "timecode.h"
#include "missionmodel.h"
#include <QMessageBox>

ProcessDialog::ProcessDialog(QStringList lines, QWidget *parent) :
  QDialog(parent),
  ui(new Ui::ProcessDialog),
  missionList(&lines)
{
  ui->setupUi(this);
  setModal(Qt::ApplicationModal);

  globalCanceled = false;

  MissionModel *model = new MissionModel(&missionList);
  ui->missionTable->setModel(model);
//  ui->missionTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
  ui->missionTable->setColumnWidth(0, 170);
  ui->missionTable->setColumnWidth(1, 170);
//  ui->missionTable->setColumnWidth(2, 30);
  ui->missionTable->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);

  ui->totalProgress->setMaximum(missionList.size());
  ui->totalProgress->setMinimum(0);
  ui->totalProgress->setValue(0);


  currentProcess = new QProcess(this);
  currentProcess->setReadChannelMode(QProcess::MergedChannels);
  currentProcess->setReadChannel(QProcess::StandardOutput);

  connect(ui->actionCancelCurrentMission, &QAction::triggered, this, &ProcessDialog::cancelCurrentMission);

  connect(ui->actionQuitAllMission, &QAction::triggered,
          this, &ProcessDialog::quitAllMissions);


  //process signals

  connect(currentProcess, &QProcess::started, [ = ]() {
    this->currentMission->status = Mission::WORKING;
  });

  connect(currentProcess, &QProcess::readyRead, this, &ProcessDialog::handleOutputs);

  connect(currentProcess, QOverload<int>::of(&QProcess::finished),
          this, &ProcessDialog::currentFinished);

  //ui
  connect(currentProcess, &QProcess::started, [ = ]() {
    ui->cancelCurrentButton->setEnabled(true);
    ui->quitAllButton->setEnabled(true);
    ui->missionTable->viewport()->update();
  });
  connect(currentProcess, QOverload<int>::of(&QProcess::finished), [ = ]() {
    ui->cancelCurrentButton->setEnabled(false);
    ui->quitAllButton->setEnabled(false);
    ui->missionTable->viewport()->update();
  });
}

ProcessDialog::~ProcessDialog()
{
  currentProcess->kill();
  currentProcess->deleteLater();
  delete ui;
}

void ProcessDialog::startProcess()
{
  currentProcess->waitForFinished(5000);
  currentCanceled = false;
  if (missionList.isEmpty()) {
    QMessageBox::warning(this, tr("运行个啥呀？"), tr("运行个毛线！"), QMessageBox::Ok);
    return;
  }
  Mission *new_mission;
  new_mission = missionList.nextWaiting();
  if (new_mission != nullptr) {
    currentMission = new_mission;
  }
  if (currentMission->status == Mission::WAITING) {
    currentProcess->start(
      currentMission->ffmpeg,
      currentMission->fullArgs
    );
  }
}

void ProcessDialog::handleOutputs()
{
  QString line = currentProcess->readAll().simplified();

  if (line.contains("Duration: ") && line.contains("fps")) {
    QRegExp duration_exp("Duration: (.{11}),");
    QRegExp fps_exp(" (\\d+) fps,");
    duration_exp.indexIn(line);
    fps_exp.indexIn(line);
    QString time_stamp = duration_exp.capturedTexts()[1];
    qDebug() << time_stamp;
    int currentFps = fps_exp.capturedTexts()[1].toInt();
    qDebug() << currentFps;
    ui->currentProgress->setMaximum(
      TimeCode::timestampToFrame(time_stamp, currentFps)
    );
  }

  if (line.startsWith("frame=")) {
    qDebug() << line;
    QRegExp frame_exp("frame=([ \\d]+)fps");
    frame_exp.indexIn(line);
    int currentFrame = frame_exp.capturedTexts()[1].toInt();
    ui->currentProgress->setValue(currentFrame);

    QRegExp fps_exp("fps=([ \\d]+)q");
    fps_exp.indexIn(line);
    int codingFps = fps_exp.capturedTexts()[1].toInt();
    if (codingFps == 0)
      ui->timeLabel->setText("--:--:--");
    else {
      QList<int> last_about_time = TimeCode::frameToTimeAbout(
                                     ui->currentProgress->maximum() - currentFrame, codingFps
                                   );
      qDebug() << last_about_time;
      QString last_time = QString("%1:%2:%3").arg(last_about_time[0]).arg(last_about_time[1]).arg(last_about_time[2]);
      ui->timeLabel->setText(last_time);
    }

    QRegExp speed_exp(" speed=([ \\d\\.x]+)");
    speed_exp.indexIn(line);
    qDebug() << speed_exp.capturedTexts();
    QString speed = speed_exp.capturedTexts()[1].simplified();
    ui->speedLabel->setText(speed);
  }
//  qDebug() << line;
}

void ProcessDialog::currentFinished(int exitCode)
{
  qDebug() << "finished with code:" << currentProcess->exitCode();
  if (globalCanceled) {
    currentMission->status = Mission::CANCELED;
    MissionList::iterator i;
    for (i = missionList.begin(); i != missionList.end(); ++i) {
      if (i->status == Mission::WAITING)
        i->status = Mission::CANCELED;
    }
    return;
  }

  if (currentCanceled)
    currentMission->status = Mission::CANCELED;
  else {
    if (exitCode == 0)
      currentMission->status = Mission::DONE;
    else
      currentMission->status = Mission::ERROR;
  }

  ui->totalProgress->setValue(missionList.size() - missionList.howManyWaiting());

  if (missionList.howManyWaiting() != 0) {
    qDebug() << "starting new cycle";
    startProcess();
  }
}

void ProcessDialog::cancelCurrentMission()
{
  currentCanceled = true;
  qDebug() << "user canceled current mission";
  currentProcess->write("q");
}

void ProcessDialog::quitAllMissions()
{
  globalCanceled = true;
  qDebug() << "user canceled all missions";
  currentProcess->write("q");
}


void ProcessDialog::closeEvent(QCloseEvent *e)
{
//  if (currentProcess->state() != QProcess::NotRunning)
  quitAllMissions();
  currentProcess->waitForFinished(5000);
  e->accept();
}
